package com.lakala.sh.zf.openplatform.common;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author peijian
 * @Date 2021/1/18 16:37
 * @Version 1.0
 */
public class RSAUtil {

//    private static final Logger LOGGER = LoggerFactory.getLogger(RSAUtil.class);

    private static final int KEYSIZE =2048;

    private static final String KEY_ALGORITHM = "RSA";
    private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";

    public static final String DEFAULT_SEED = "$%^*%^()(ED47d784sde78";

    public static final String PUBLIC_KEY = "PublicKey";
    public static final String PRIVATE_KEY = "PrivateKey";


    /**
     * 生成秘钥
     * @param seed 种子
     * @return
     * @throws Exception
     */
    public static Map<String, Key> initKey(String seed) throws Exception {
//        LOGGER.info("生成密钥");
        System.out.println("生成秘钥");
        KeyPairGenerator keygen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        SecureRandom secureRandom = new SecureRandom();
        // 如果指定seed，那么secureRandom结果是一样的，所以生成的公私钥也永远不会变
//		secureRandom.setSeed(seed.getBytes());
        // Modulus size must range from 512 to 1024 and be a multiple of 64
        keygen.initialize(KEYSIZE, secureRandom);
        KeyPair keys = keygen.genKeyPair();
        PrivateKey privateKey = keys.getPrivate();
        PublicKey publicKey = keys.getPublic();
        Map<String, Key> map = new HashMap<String, Key>(2);
        map.put(PUBLIC_KEY, publicKey);
        map.put(PRIVATE_KEY, privateKey);
        return map;
    }

    /**
     * 生成默认秘钥
     * @return
     * @throws Exception
     */
    public static Map<String, Key> initKey() throws Exception {
        return initKey(DEFAULT_SEED);
    }

    /**
     * 取得私钥
     * @param keyMap
     * @return
     * @throws Exception
     */
    public static String getPrivateKey(Map<String, Key> keyMap) throws Exception {
        Key key = (Key) keyMap.get(PRIVATE_KEY);
        // base64加密私钥
        return encryptBASE64(key.getEncoded());
    }


    /**
     * 取得公钥
     * @param keyMap
     * @return
     * @throws Exception
     */
    public static String getPublicKey(Map<String, Key> keyMap) throws Exception {
        Key key = (Key) keyMap.get(PUBLIC_KEY);
        // base64加密公钥
        return encryptBASE64(key.getEncoded());
    }


    /**
     * 用私钥对信息进行数字签名
     * @param data  加密数据
     * @param privateKey  私钥-base64加密的
     * @return
     * @throws Exception
     */
    public static String signByPrivateKey(byte[] data, String privateKey) throws Exception {
        System.out.println("用私钥对信息进行数字签名");
        byte[] keyBytes = decryptBASE64(privateKey);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey priKey = factory.generatePrivate(keySpec);// 生成私钥
        // 用私钥对信息进行数字签名
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(priKey);
        signature.update(data);
        return encryptBASE64(signature.sign());

    }

    /**
     * BASE64Encoder加密
     * @param data 要加密的数据
     * @return  加密后的字符串
     */
    private static String encryptBASE64(byte[] data) {
        return new String(Base64.encodeBase64(data));
    }

    private static byte[] decryptBASE64(String data) {
        return Base64.decodeBase64(data);
    }


    public static boolean verifyByPublicKey(byte[] data, String publicKey, String sign) throws Exception {
        byte[] keyBytes = decryptBASE64(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey pubKey = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(pubKey);
        signature.update(data);
        return signature.verify(decryptBASE64(sign)); // 验证签名
    }


    public static void main(String[] args) throws Exception {
        String signStr = "testcontent17652ohkjs";
        System.out.println(signStr);
        Map<String, Key> keyMap = initKey();// 构建密钥
        PublicKey publicKey = (PublicKey) keyMap.get(PUBLIC_KEY);
        PrivateKey privateKey = (PrivateKey) keyMap.get(PRIVATE_KEY);
        System.out.println("私钥format：{}"+privateKey.getFormat());
        System.out.println("公钥format："+publicKey.getFormat());
        System.out.println("私钥string："+getPrivateKey(keyMap));
        System.out.println("公钥string："+getPublicKey(keyMap));
        // 产生签名
        String sign = signByPrivateKey(signStr.getBytes(), getPrivateKey(keyMap));
        System.out.println("签名sign="+sign);
        // 验证签名
        boolean verify1 = verifyByPublicKey(signStr.getBytes(), getPublicKey(keyMap), sign);
        System.out.println("经验证数据和签名匹配："+verify1);

        test();

    }


    private static void test() throws Exception {
        String privateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDPq651FjlA3KPMNP573D5HYlA1kjvgBr7xDuN0ss2tUYOfM6oOE42ucQZoaSa35acUce+4zSSTQm3bLsTIH/3Hm1BY0hfnkrSBPOoAr9JVZhafRB7dQDIeJSc/fQadxNbKGi4qZUkO90Jkh5RcSU/p3ScSNZzkronfDcPvKkZxU8AqtTD1yOdijT+De4MstzyYMHfv/UKb7tHA8abJNuX35xwJFxzV+xxmnSJItbNi0f462Bu9GMZla/FYdLlf088ajxh955gCdYa+okpF3/352hFC0+A9/WUEzdzSkcgkjbkSQTmqXgDNP9TX1zIkCj1c/04X4baHneUslXRT+eMvAgMBAAECggEAPxsRgX0GWuJxV92Gs4bC2hhS/WR5k2MZZNE8Zzrqa0+I6rjdZTel5ytrYhEJ9fnwYrMYwJR+F82o6mD05Udra9uTd9on73PSLC+hgCHtjYvfNfiSVHNsh2KM4asRdqHZD0MTYkizAbw7TacxezW/9fYBKHRoP8mWFdTuBGBZVZgse2tbRUDniM7QdGBmDT6H8wNl25CKoUm8pxUBCbPrtjTh4BFhuilrq+iEVvZPBEtH70OFehK/G21FfI1ouuRNb2cUArgmlnnrKcN1+3XdzXSNQsxWnBZkrVLaRFDXRfCI0BJNE2bPiSfwxji42LWjR1uKdyjMaFMDaMYMrP4aSQKBgQDoHNmf6FTdGIeLdjqSHafYS+1Hg3vtMYmOPjzmx3MKopdoyEU1di4HRFhzGFjhjnzezSRvNmfJjqEmmGD8SRIJbN/DPMC8p1F/R8O9hOBc6wwE2ff3dRyFa7Oq82OhUPpz/BCESDimplsL9C9PPcwowNnuMDG2YFhIr/iz/MjK+wKBgQDlCuPtFXjqMeB1yA8f2rIabZ2i0VTxsQo3EdIyzXJ+ld9cznLvuQXw1AHCirWepbsLUR7BoDR2Zy7xjD+iMXFWJ8wb9skhOcoQcOJH6xlzYZWLDIeDbuvxvVUtWET/58xPHkzR2OyWP21T2IRusB5HPpEMHAqAtgRnNQGQfr+SXQKBgQCOUspaU8Jdg6HxMMB/QbHeXcgTlprReROIZb9AHsH6nnHKrSpKurlEeXLmt+IgBBerIgyaKLkBDPThToQBjeiCYQDfnQvtYYcGTYHHXoeYUgOfoet7D5M6eCzFwNGxY47+uWuDQSmDffPL46FyrEjYIFBAzcpdsrvPbh9IddLFKwKBgQCJls4u2MxHG2k0N9bmEtEU0S515Xw6qFhzlnAH9qTF6DBCpv4ihapM7n6UKBFMWVCQTs3EEQIS8o8fqVl8jGkCEWwqjEhsfjOlRrqX62HhjwhvfDpXuSVhlZP6ZmEkvVFdYd1R3hbZdwas7I85kvDNaYdml92zTiQ8/3mOHKXmPQKBgHhFPQPCfyPxktTQDvz1NXZ4H+jH6t75ymXzqhOt3IYBGTk394X67r9R9dKFlDEkCwVyYvrEllAMiy31IMyihYYP4L2FHuImfOpY78Ydd3NJUIJ1fZVZ+9IaoQxnVTlvULq5UNFNkjA+qb4DNHKqLti0+ZtOV6uuVEMXfXwZtCOa";
        String authcode = "6219760850804724334";
        // 产生签名
        String qrNoIdentifier = MessageDigestUtil.getSHA256Digest(authcode);
        Map<String, String> map = Maps.newHashMap();
        map.put("qrNoIdentifier", qrNoIdentifier);
        StringBuilder signStr = new StringBuilder("qrNoIdentifier=");
        signStr.append(qrNoIdentifier);
        String sign = signByPrivateKey(signStr.toString().getBytes(), privateKey);
        System.out.println("签名sign="+sign);
        map.put("signature", sign);
        String jsonStr = JSONObject.toJSONString(map);
        System.out.println("get info request params=" +jsonStr);
//        // 验证签名
        boolean verify1 = verifyByPublicKey(signStr.toString().getBytes(), "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz6uudRY5QNyjzDT+e9w+R2JQNZI74Aa+8Q7jdLLNrVGDnzOqDhONrnEGaGkmt+WnFHHvuM0kk0Jt2y7EyB/9x5tQWNIX55K0gTzqAK/SVWYWn0Qe3UAyHiUnP30GncTWyhouKmVJDvdCZIeUXElP6d0nEjWc5K6J3w3D7ypGcVPAKrUw9cjnYo0/g3uDLLc8mDB37/1Cm+7RwPGmyTbl9+ccCRcc1fscZp0iSLWzYtH+OtgbvRjGZWvxWHS5X9PPGo8YfeeYAnWGvqJKRd/9+doRQtPgPf1lBM3c0pHIJI25EkE5ql4AzT/U19cyJAo9XP9OF+G2h53lLJV0U/njLwIDAQAB", sign);
        System.out.println("经验证数据和签名匹配：" +verify1);
    }

}
